#include "stdafx.h"

#include "MenuBar.h"
#include "Theme.h"
#include "Settings.h"

#ifdef _DEBUG
#include "crtdbg.h"
#endif

Menu::Menu(HWND hParent)
  : parent(hParent)
{
  ZeroMemory(&rect, sizeof(rect));
  longTapTimer.Create(this);
}

Menu::~Menu()
{
}

void Menu::Draw(HDC hdc)
{
  if (items.size() == 0)
    return;

  int x = rect.left;
  int wDest = Theme::MenuStretch ?
                (rect.right - rect.left) / items.size()
              : 0;
  int hDest = Theme::MenuStretch ?
                rect.bottom - rect.top
              : 0;
  int step = (wDest == 0) ? Theme::iMenuButtonWidth : wDest;

  // draw buttons
  size_t n = items.size();
  for (size_t i = 0; i < n; i++)
  {
    if (items[i].state & misHidden)
      continue;

    DrawItem(hdc, items[i], x, rect.top, wDest, hDest);

    x += step;
    if (x > rect.right)
      break;
  }

  // if some space left
  if (x < rect.right && items.size() > 0)
  {
    Theme::DrawMenuBg(hdc, x, rect.top, 
      rect.right - x, hDest ? hDest : Theme::iMenuButtonHeight,
      items[0].themeItem);
  }
}

void Menu::OnMouseDown(int x, int y)
{
  skipMouseAction = false;

  int idx = GetItem(x);
  SetHover(idx);
  InvalidateRect(parent, &rect, FALSE);
  if (idx != -1)
  {
    if (Settings::longTapDelay > 0)
    {
      longTapTimer.Start(Settings::longTapDelay);
    }
    else
    {
      longTapTimer.Start(MENU_LONGTAP_DURATION);
    }

    longTapTimer.Start(Settings::longTapDelay);
  }
}

void Menu::OnMouseMove(int x, int y)
{
  if (skipMouseAction)
    return;

  int idx = GetItem(x);
  if (idx != -1 && idx != GetHovered())
  {
    longTapTimer.Stop();
    SetHover(idx);
    InvalidateRect(parent, &rect, FALSE);
  }
}

void Menu::OnMouseUp(int x, int y)
{
  if (skipMouseAction)
    return;

  longTapTimer.Stop();

  SetHover();
  int idx = GetItem(x);
  if (idx != -1)
  {
    SendCommand(parent, items[idx].command);
  }
  InvalidateRect(parent, &rect, FALSE);
}

int  Menu::GetItem(int x)
{
  if (items.size() == 0)
    return -1;

  int cx = rect.left;
  int step = Theme::MenuStretch ?
                 (rect.right - rect.left) / items.size()
               : Theme::iMenuButtonWidth;

  size_t n = items.size();
  for (size_t i = 0; i < n; i++)
  {
    if (items[i].state & misHidden)
      continue;

    if (x >= cx && x < cx + step)
      return i;

    cx += step;
    if (cx > rect.right)
      break;
  }

  return -1;
}

int  Menu::GetItemAt(int num)
{
  if (num < 0 || num >= (int)items.size())
    return -1;

  size_t n = items.size();
  for (size_t i = 0; i < n; i++)
  {
    if (items[i].state & misHidden)
      continue;

    num--;
    if (num < 0)
      return i;
  }

  return -1;
}

int  Menu::GetItemCommand(int idx)
{
  if (idx >= 0 && idx < (int)items.size())
    return items[idx].command;
  return CMD_NONE;
}

int  Menu::GetItemIndex(int command)
{
	size_t n = items.size();
	for (size_t i = 0; i < n; i++)
  {
    if (items[i].command == command)
      return i;
  }
  return -1;
}

bool Menu::GetSelected(int item)
{
  if (item >= 0 && item < (int)items.size())
    return (items[item].state & misSelected) != 0;
  else
    return false;
}
int  Menu::GetSelection()
{
	size_t n = items.size();
	for (size_t i = 0; i < n; i++){
		if (items[i].state & misSelected)
			return i;
	}
  return -1;
}

bool Menu::GetHover(int item)
{
  if (item >= 0 && item < (int)items.size())
    return (items[item].state & misHover) != 0;
  else
    return false;
}
int  Menu::GetHovered()
{
	size_t n = items.size();
	for (size_t i = 0; i < n; i++)
      if (items[i].state & misHover)
        return i;
  return -1;
}

void Menu::SetItemStateBit(int item, MenuItemState bit, bool set)
{
  if (item >= 0 && item < (int)items.size())
  {
    if (set)
      items[item].state |= bit;
    else
      items[item].state &= bit ^ 0xFF;
  }
}
bool Menu::GetItemStateBit(int item, MenuItemState bit)
{
  if (item >= 0 && item < (int)items.size())
    return (items[item].state & bit) != 0;
  else
    return false;
}

void Menu::SetSelected(int item, bool select, bool exclusive)
{
	size_t n = items.size();
  for (size_t i = 0; i < n; i++)
  {
    if (i == item)
    {
      if (select)
        items[i].state |= misSelected;
      else
        items[i].state &= misSelected ^ 0xFF;
    }
    else if (select && exclusive)
    {
      items[i].state &= misSelected ^ 0xFF;
    }
  }
}

void Menu::SetHover(int item)
{
  size_t n = items.size();
  for (size_t i = 0; i < n; i++)
  {
    if (i == item)
    {
      items[i].state |= misHover;
    }
    else
    {
      items[i].state &= misHover ^ 0xFF;
    }
  }
}

bool Menu::AddItem(int command, EMenuItems themeItem)
{
  MenuItem item;
  item.command = command;
  item.themeItem = themeItem;
  items.push_back(item);

  return true;
}

void Menu::OnLongTapTimer(UINT nID, DWORD dwTime)
{
  longTapTimer.Stop();
  skipMouseAction = true;
  int idx = GetHovered();
  if (idx >= 0)
  {
    SendCommandF(parent, items[idx].command, CMDF_MENU_LONGTAP);
  }
  SetHover();

  InvalidateRect(parent, &rect, FALSE);
}

void Menu::DrawItem(HDC hdc, MenuItem& item, int x, int y, int cx, int cy)
{
  Theme::DrawMenuItem(hdc, x, y, cx, cy, item.themeItem, IsSelectedLook(item));
}

ListMenu::ListMenu(HWND hWnd, int selection, CallType logType)
  : Menu(hWnd)
{
  AddItem(CMD_LIST_FAVORITES, miTabFavorites);
  AddItem(CMD_LIST_CALLLOG,   miTabCallLog);
  AddItem(CMD_LIST_CONTACTS,  miTabContacts);
  AddItem(CMD_LIST_DIALER,    miDialer);
  AddItem(CMD_LIST_KEYBOARD,  miKeyboard);

  //{ miCallLogMissed, miCallLogIncoming, miCallLogOutgoing };
  callLogType = logType;

  SetSelected(selection);
}

ListMenu::~ListMenu()
{
}

void ListMenu::DrawItem(HDC hdc, MenuItem& item, int x, int y, int cx, int cy)
{
  // if call log is selected and between Missed and Outgoing, draw it separately
  if (item.command == CMD_LIST_CALLLOG && IsSelectedLook(item))
  {
    EMenuItems titem;
    switch(callLogType)
    {
    case ctMissed:   titem = miCallLogMissed;   break;
    case ctIncoming: titem = miCallLogIncoming; break;
    case ctOutgoing: titem = miCallLogOutgoing; break;
    default:         titem = miTabCallLog;      break;
    }
    Theme::DrawMenuItem(hdc, x, y, cx, cy, titem, true);
  }
  else
  {
    Menu::DrawItem(hdc, item, x, y, cx, cy);
  }
}

DetailsMenu::DetailsMenu(HWND hWnd)
  : Menu(hWnd)
{
  AddItem(CMD_DETAILS_BACK,     miBack);
  AddItem(CMD_DETAILS_VIEW,     miContactView);
  AddItem(CMD_DETAILS_EDIT,     miContactEdit);
  AddItem(CMD_DETAILS_DELETE,   miContactDelete);
  AddItem(CMD_DETAILS_FAVORITE, miContactFavorite);
}

DetailsMenu::~DetailsMenu()
{
}

CallDetailsMenu::CallDetailsMenu(HWND hWnd)
  : Menu(hWnd)
{
  AddItem(CMD_DETAILS_BACK,        miBack);
  AddItem(CMD_DETAILS_CL_NEWCONTACT,  miContactAdd);
  AddItem(CMD_DETAILS_CL_GOTOCONTACT, miContactView);
  AddItem(CMD_DETAILS_CL_DELETECALL,  miContactDelete);
}

CallDetailsMenu::~CallDetailsMenu()
{
}

SimDetailsMenu::SimDetailsMenu(HWND hWnd)
  : Menu(hWnd)
{
  AddItem(CMD_DETAILS_BACK,        miBack);
  AddItem(CMD_DETAILS_SIM_NEWCONTACT,  miContactAdd);
  AddItem(CMD_DETAILS_SIM_GOTOOUTLOOK, miOutlook);
}

SimDetailsMenu::~SimDetailsMenu()
{
}